#include "Camera.h"
#include "Timer.h"
#include "InputManager.h"
#include "ScreenResolution.h"

Camera::Camera(void)
{
	m_position = Vector3(0, 0, 0);
	m_rotateAngle = Vector3(0, 0, 0);
	m_fovY = PI/4;
	m_aspect = ScreenResolution::GetInstance()->GetScreenRatio();
	m_nearPlane = 0.1;
	m_farPlane = 500;
	CalculateProjectMatrix();
}

Camera::~Camera(void)
{
}

void Camera::Init(GLfloat fovY, GLfloat aspect, GLfloat nearPlane, GLfloat farPlane, GLfloat speed)
{
	m_fovY = fovY;
	m_aspect = aspect;
	m_nearPlane = nearPlane;
	m_farPlane = farPlane;
	m_speed = speed;
	CalculateProjectMatrix();
}

void Camera::CalculateProjectMatrix()
{
	m_projectMatrix.SetPerspective(m_fovY, m_aspect, m_nearPlane, m_farPlane);
}

Matrix Camera::CalculateViewProjectMatrix()
{
	Matrix translateMatrix;
	translateMatrix.SetTranslation(-m_position.x, -m_position.y, -m_position.z);

	Matrix rotateMatrix, rotateX, rotateY, rotateZ;
	rotateX.SetRotationX(-m_rotateAngle.x);
	rotateY.SetRotationY(-m_rotateAngle.y);
	rotateZ.SetRotationZ(-m_rotateAngle.z);
	rotateMatrix = rotateY * rotateX * rotateZ;

	Matrix viewProjectMatrix = (translateMatrix * rotateMatrix) * m_projectMatrix;
	/*Matrix worldMatrix = CalculateWorldMatrix();
	Matrix viewMatrix = worldMatrix.Inverse();*/
	return viewProjectMatrix;
}

Matrix Camera::CalculateWorldMatrix()
{
	Matrix translateMatrix;
	translateMatrix.SetTranslation(m_position);

	Matrix rotateMatrix;
	rotateMatrix.SetRotation(m_rotateAngle);

	Matrix worldMatrix = rotateMatrix * translateMatrix;

	return worldMatrix;
}

void Camera::Update()
{
	InputManager *inputManager = InputManager::GetInstance();

	if (inputManager->IsKeyDown(38))
	{
		Rotate(UP);
	}

	if (inputManager->IsKeyDown(37))
	{
		Rotate(LEFT);
	}

	if (inputManager->IsKeyDown(39))
	{
		Rotate(RIGHT);
	}

	if (inputManager->IsKeyDown(40))
	{
		Rotate(DOWN);
	}

	if (inputManager->IsKeyDown(65))
	{
		Move(LEFT);
	}

	if (inputManager->IsKeyDown(68))
	{
		Move(RIGHT);
	}

	if (inputManager->IsKeyDown(87))
	{
		Move(FORWARD);
	}

	if (inputManager->IsKeyDown(83))
	{
		Move(BACKWARD);
	}

	static int xtmp, ytmp;
	if (inputManager->IsMouseDown())
	{
		xtmp = inputManager->GetXmouse();
		ytmp = inputManager->GetYmouse();
	}

	if (inputManager->IsDrag())
	{
		int dx = inputManager->GetXmouse() - xtmp;
		int dy = inputManager->GetYmouse() - ytmp;
		if (dx > 0)
		{
			for (int i = 0; i < dx; i++)
			{
				Rotate(RIGHT);
			}
		}
		else if (dx < 0)
		{
			for (int i = 0; i < dx * -1; i++)
			{
				Rotate(LEFT);
			}
		}
		if (dy > 0)
		{
			for (int i = 0; i < dy; i++)
			{
				Rotate(DOWN);
			}
		}
		else if (dy < 0)
		{
			for (int i = 0; i < dy * -1; i++)
			{
				Rotate(UP);
			}
		}
		xtmp = inputManager->GetXmouse();
		ytmp = inputManager->GetYmouse();
	}
}

void Camera::Move(Direction direction)
{
	Vector4 moveL;
	switch (direction)
	{
		case FORWARD:
			moveL = Vector4(0, 0, -Timer::FrameTime() * m_speed, 1);
			break;
		case BACKWARD:
			moveL = Vector4(0, 0, Timer::FrameTime() * m_speed, 1);
			break;
		case RIGHT:
			moveL = Vector4(Timer::FrameTime() * m_speed, 0, 0, 1);
			break;
		case LEFT:
			moveL = Vector4(-Timer::FrameTime() * m_speed, 0, 0, 1);
			break;
	}
	Matrix worldMatrix = CalculateWorldMatrix();
	Vector4 moveW = moveL * worldMatrix;
	m_position = Vector3(moveW.x, moveW.y, moveW.z);
}

void Camera::Rotate(Direction direction)
{
	switch (direction)
	{
		case UP:
			m_rotateAngle.x += Timer::FrameTime() * m_speed;
			break;
		case DOWN:
			m_rotateAngle.x -= Timer::FrameTime() * m_speed;
			break;
		case RIGHT:
			m_rotateAngle.y -= Timer::FrameTime() * m_speed;
			break;
		case LEFT:
			m_rotateAngle.y += Timer::FrameTime() * m_speed;
			break;
	}
}